package cn.com.nes.site.service.system.region.impl;

import cn.com.nes.common.exception.IllegalBusinessException;
import cn.com.nes.common.exception.MissBusinessParameterException;
import cn.com.nes.common.util.XzqhUtils;
import cn.com.nes.mybatis.agent.ope.mapper.XzqhMapper;
import cn.com.nes.mybatis.agent.system.entity.SystemXzqh;
import cn.com.nes.mybatis.agent.system.mapper.SystemXzqhMapper;
import cn.com.nes.mybatis.callcenter.mapper.TXzqhMapper;
import cn.com.nes.site.service.system.region.XzqhService;
import cn.com.nes.site.service.system.region.dto.RegionCodeTreeNode;
import cn.com.nes.site.service.system.region.dto.RegionDTO;
import cn.com.nes.site.service.system.region.dto.XzqhDTO;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class XzqhServiceImpl extends ServiceImpl<SystemXzqhMapper, SystemXzqh> implements XzqhService {

    @Resource
    private TXzqhMapper tXzqhMapper;

    @Resource
    private XzqhMapper xzqhMapper;

    @Override
    public String getAreaCodePrefix(String areaCode) {
        String prefix = "";
        if (StrUtil.isNotBlank(areaCode)) {
            String areaLevel = tXzqhMapper.getAreaCodeLevel(areaCode); // 获取行政区划级别
            String prefixLength = XzqhUtils.subXzqhDigit(areaLevel);   // 根据级别查询前缀长度
            prefix = areaCode.substring(0, Integer.parseInt(prefixLength));     // 截取前缀
        }
        return prefix;
    }

    @Override
    public String getUserAreaCode(String userId) {
        return tXzqhMapper.getAreaCodeByUserId(userId);
    }

    @Override
    public List<RegionCodeTreeNode> getRegionCodeList(List<String> regionCodeList) {
        if (CollUtil.isEmpty(regionCodeList)) {
            return Collections.emptyList();
        }
        return this.baseMapper.getRgionCodeList(regionCodeList);
    }

    @Override
    public List<XzqhDTO> getXzqhListByXzqhdmList(List<String> xzqhdmList) {
        if (CollectionUtil.isEmpty(xzqhdmList)) return new ArrayList<>();

        List<XzqhDTO> xzqhList = xzqhMapper.getXzqhList(xzqhdmList);
        if (CollectionUtil.isEmpty(xzqhdmList)) return xzqhList;

        for (XzqhDTO xzqhDTO : xzqhList) {
            setChildList(xzqhDTO);
        }
        return xzqhList;
    }

    @Override
    public Map<String, BigDecimal> getCoordinate(String areaCode) {
        if (StrUtil.isBlank(areaCode)) return new HashMap<>();

        XzqhDTO xzqhDTO = xzqhMapper.getXzqhDetailByAreaCode(areaCode);
        Map<String, BigDecimal> res = new HashMap<>();
        if (ObjectUtil.isNotNull(xzqhDTO)) {
            res.put("longitude", xzqhDTO.getZxjd());
            res.put("latitude", xzqhDTO.getZxwd());
        }
        return res;
    }

    @Override
    public String getAreaName(String areaCode) {
        XzqhDTO areaInfo = xzqhMapper.getXzqhDetailByAreaCode(areaCode);
        if (ObjectUtil.isNull(areaInfo)) {
            return StrUtil.EMPTY;
        }
        return areaInfo.getXzqhqc();
    }

    @Override
    public String getAreaName(String delimiter, Set<String> areaCodeSet) {
        if (CollectionUtil.isEmpty(areaCodeSet)) {
            return StrUtil.EMPTY;
        }

        QueryWrapper<SystemXzqh> wrapper = new QueryWrapper<>();
        wrapper.select("xzqhmc");
        wrapper.in("xzqhdm", areaCodeSet);

        List<SystemXzqh> systemXzqhs = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(systemXzqhs)) {
            return StrUtil.EMPTY;
        }

        return systemXzqhs.stream().map(SystemXzqh::getXzqhmc).collect(Collectors.joining(delimiter));
    }

    @Override
    public List<String> getChildAreaCodesByParentAreaCodeList(List<String> parentAreaCodeList, boolean retainParentAreaCode) throws Exception {
        if (CollectionUtil.isEmpty(parentAreaCodeList)) {
            throw new IllegalBusinessException("parentAreaCodeList must not be null");
        }

        Set<String> resSet = new HashSet<>();
        for (String parentAreaCode : parentAreaCodeList) {
            List<SystemXzqh> systemXzqhs = this.getListByPrefix(XzqhUtils.getRegionCodePrefix(parentAreaCode));
            if (CollectionUtil.isNotEmpty(systemXzqhs)) {
                resSet.addAll(systemXzqhs.stream().map(SystemXzqh::getXzqhdm).collect(Collectors.toSet()));
            }
        }

        if (!retainParentAreaCode) {
            resSet = resSet.stream().filter(areaCode -> !parentAreaCodeList.contains(areaCode)).collect(Collectors.toSet());
        }
        return new ArrayList<>(resSet);
    }

    @Override
    public Set<String> getChildAreaCodesByParentAreaCodeSet(Set<String> parentSet, boolean retainParentAreaCode) throws Exception {
        if (CollectionUtil.isEmpty(parentSet)) {
            throw new IllegalBusinessException("parentSet must not be null");
        }

        Set<String> resSet = new HashSet<>();
        for (String parentAreaCode : parentSet) {
            List<String> areaCodeList = this.baseMapper.getAreaCodeByPrefix(XzqhUtils.getRegionCodePrefix(parentAreaCode));
            resSet.addAll(areaCodeList);
        }

        if (!retainParentAreaCode) {
            resSet = resSet.stream().filter(areaCode -> !parentSet.contains(areaCode)).collect(Collectors.toSet());
        }
        return resSet;
    }

    @Override
    public List<XzqhDTO> getChildListByAreaCode(String areaCode) throws Exception {
        if (StrUtil.isBlank(areaCode)) {
            throw new Exception("areaCode must not be null");
        }
        return xzqhMapper.getChildList(XzqhUtils.getRegionCodePrefix(areaCode), String.valueOf(XzqhUtils.getRegionLevel(areaCode) + 1));
    }

    @Override
    public XzqhDTO getAreaInfo(String areaCode) throws Exception {
        if (StrUtil.isBlank(areaCode)) {
            throw new Exception("areaCode must not be null");
        }
        if (1 == XzqhUtils.getRegionLevel(areaCode)) {
            areaCode = XzqhUtils.getRegionCodePrefix(areaCode);
        }

        XzqhDTO areaInfo = xzqhMapper.getXzqhDetailByAreaCode(areaCode);
        if (ObjectUtil.isNull(areaInfo)) {
            throw new Exception("行政区划信息不存在!");
        }
        return areaInfo;
    }

    @Override
    public Set<String> handleAreaCodeList(boolean handleType, boolean checkEmptyCollection, List<String>... areaCodeListCollection) throws Exception {
        if (ObjectUtil.isNull(areaCodeListCollection)) {
            throw new Exception("areaCodeListCollection must not be null");
        }

        Set<String> areaCodeSet = new HashSet<>();

        // 如果是取交集
        if (handleType) {
            for (List<String> areaCodeList : areaCodeListCollection) {
                if (CollectionUtil.isEmpty(areaCodeList)) {
                    if (checkEmptyCollection) {
                        // 跳过空集合
                        continue;
                    } else {
                        return areaCodeSet;
                    }
                }
                if (CollectionUtil.isEmpty(areaCodeSet)) {
                    areaCodeSet.addAll(areaCodeList);
                    continue;
                }
                // 暴力循环 时间复杂度 = O(n)
                areaCodeSet.removeIf(areaCode -> areaCodeList.stream().noneMatch(n -> n.equals(areaCode)));
            }
            return areaCodeSet;
        }

        // 如果是取并集
        for (List<String> areaCodeList : areaCodeListCollection) {
            areaCodeSet.addAll(areaCodeList);
        }
        return areaCodeSet;
    }

    @Override
    public List<SystemXzqh> getListByPrefix(String regionCodePrefix) throws Exception {
        if (StrUtil.isBlank(regionCodePrefix)) {
            throw new MissBusinessParameterException("regionCodePrefix must not be null");
        }

        return this.baseMapper.getListByPrefix(regionCodePrefix);
    }

    @Override
    public List<RegionDTO> getRegionCodes(List<String> regionCodes) {
        if (CollUtil.isEmpty(regionCodes)) {
            return Collections.emptyList();
        }
        return this.baseMapper.getRgionCodes(regionCodes);
    }

    // 设置子级节点
    private void setChildList(XzqhDTO xzqhDTO) {
        if ("5".equals(xzqhDTO.getXzqhjb())) return;

        // 获取当前级别
        Integer thisLevel = Integer.parseInt(xzqhDTO.getXzqhjb());
        // 下一级的级别
        Integer childLevel = thisLevel + 1;

        // 截取当前级别有效编码
        String thisCode = xzqhDTO.getXzqhdm();
        switch (thisLevel) {
            case 1:
                thisCode = thisCode.substring(0, 2);
                break;
            case 2:
                thisCode = thisCode.substring(0, 4);
                break;
            case 3:
                thisCode = thisCode.substring(0, 6);
                break;
            case 4:
                thisCode = thisCode.substring(0, 9);
                break;
            default:
                break;
        }

        List<XzqhDTO> childList = xzqhMapper.getChildList(thisCode, String.valueOf(childLevel));
        xzqhDTO.setChildList(childList);

     /*   // 如果入参节点是四级，那么说明其子级是五级，则不用再递归了
        if (CollectionUtil.isNotEmpty(childList) && !"4".equals(xzqhDTO.getXzqhjb())) {
            for (XzqhDTO dto : childList) {
                setChildList(dto);
            }
        }*/
    }
}
